#ifndef PUSHSERVER_SQLSERVER_H
#define PUSHSERVER_SQLSERVER_H

#include <set>
#include <config/Config.h>
#include <connector/include/mysql/jdbc.h>
#include <logger/Logger.h>
#include "SQLServerErrorCode.h"

using namespace std;
using sql::SQLException;

typedef struct TableCreateSql {
    const char *name;
    vector<const char *> query;

    bool operator<(const TableCreateSql &tp) const {
        if (strcmp(this->name, "user") == 0)return true;
        return this->name < tp.name;
    }
} TableCreateSql;

//class AutoResultSet:public sql::ResultSet {
//public:
//    ~AutoResultSet();
//} ;

class SQLServer {
    typedef sql::mysql::MySQL_Driver
            MySQL_Driver;

    typedef shared_ptr<sql::Connection>
            Connection;

    typedef shared_ptr<sql::Statement>
            Statement;

    typedef unique_ptr<sql::ResultSet>
            ResultSet;
private:
    Connection conn = nullptr;
    /**默认游标，自动提交，某些操作不使用*/
    Statement stm = nullptr;
    Logger *logger = new Logger("SqlServer");

    /**出现无法继续的错误时调用，程序会退出
     *
     * @param msg 打印的信息
     */
    inline void error_exit(const string &msg);

    void log_sql_error(const SQLException &e);

    /**对用户的参数实行转义等操作
     *
     * @param str 要转义的字符串
     * @return 转以后的字符串
     */
    string escape_sql_str(const string &str);

//    string Template2String( t)

public:
    /**在数据库中使用COUNT
     *
     * @param field_value 对应的字段与值
     * @param table_name 表的名称
     * @return 查找结果
     */
    bool find(const pair<string, string> &field_value, const string &table_name);

    /**查找是否存在token
     *
     * @param token 要查找的token
     * @return 是否存在
     */
    bool find_token(const string &token);

    /**链接数据库，并切换架构
     */
    SQLServer(const SQLServerConfig &config);

    /**初始化 创建 不存在的表
     *
     * @return 初始化是否成功
     */
    bool init();

    enum Template {
        txt,
        html,
        json,
        markdown,
        NotFound
    };

    /** 用户发送数据时调用此函数，会向sent中插入数据
     *
     * @param title 消息标题
     * @param content 消息内容
     * @param tmp 消息类型
     * @return code,msg
     */
    const ErrorCode &sent(const string &title, const string &content, const string &token, Template tmp);

    /**发送消息后将sent中的数据转移到history
     * @param token 凭证
     * @return 返回消息，是否成功
     */
    pair<string, bool> sent2history(const string &token);

    void close();

    ~SQLServer();

private:

    vector<TableCreateSql> tables{
            {
                    "info",
                    {R"(
                create table info
                (
                    version     INT UNSIGNED default 0                 not null comment '数据库版本',
                    create_time TIMESTAMP    default CURRENT_TIMESTAMP not null comment '创建时间'
                )
                    comment '数据库信息';
    )"}
            },
            {
                    "user",
                    {R"(
                create table user
                (
                    username       INT UNSIGNED                        not null comment '用户账号',
                    password       VARCHAR(32)                         not null comment '用户密码',
                    token          VARCHAR(32)                         not null comment '凭证',
                    submit_time    TIMESTAMP default CURRENT_TIMESTAMP not null comment '注册时间',
                    last_send_time TIMESTAMP                           null comment '最后一次发送消息的时间',
                    mail           TINYTEXT                            null comment '邮箱',
                    constraint user_pk
                        primary key (username)
                )
                    comment '用户信息';)",
                            R"(create unique index user_token_uindex
                            on user (token);)"}
            },
            {
                    "sent",
                    {R"(
                create table sent
                (
                    message_id VARCHAR(36)                              comment '消息唯一编号',
                    token      VARCHAR(32)                              not null comment '凭证',
                    title      TINYTEXT                                 not null comment '消息标题',
                    content    TEXT                                     not null comment '消息内容',
                    template   ENUM ('txt', 'html', 'json', 'markdown') not null comment '消息模板',
                    time       TIMESTAMP default CURRENT_TIMESTAMP      comment '发送时间',
                    constraint sent_pk
                        primary key (message_id),
                    constraint sent_user_token_fk
                        foreign key (token) references user (token)
                )
                    comment '待发送的信息';
)"}
            },
            {
                    "history",
                    {R"(
                create table history
                (
                    message_id  VARCHAR(36)                              not null comment '消息唯一编号',
                    token       VARCHAR(32)                              not null comment '凭证',
                    title       TINYTEXT                                 not null comment '消息标题',
                    content     TEXT                                     not null comment '消息内容',
                    template    ENUM ('txt', 'html', 'json', 'markdown') not null comment '消息模板',
                    time        TIMESTAMP                                comment '发送时间',
                    receive_time TIMESTAMP default CURRENT_TIMESTAMP      comment '接收时间',
                    constraint history_pk
                        primary key (message_id),
                    constraint history_user_token_fk
                        foreign key (token) references user (token)
                )
                    comment '待发送的信息';
)"}
            },
    };
};

extern SQLServer *sqlServer;

string Template2String(SQLServer::Template temp);

SQLServer::Template String2Template(const string &s);

#endif //PUSHSERVER_SQLSERVER_H
